﻿using Ndns.ServerHost.Abstractions.Features;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;

namespace Ndns.ServerHost.Abstractions.Services
{
    public interface IContextFactoryService
    {

        ConnectionInfo CreateConnectionInfo(DnsProtocol protocol, IPAddress localIpAddress, int localPort, IPAddress remoteIpAddress, int remotePort);
        DnsContext CreateContext(string traceIdentifier, ConnectionInfo connection, IEnumerable<KeyValuePair<Type, object>> builtInFeatures, bool featureCollectionReadOnly, CancellationToken cancellationToken);

    }

    public static class ContextFactoryServiceExtensions
    {
        private static string GenerateTraceIdentifier() => Guid.NewGuid().ToString("N").Substring(0, 12).ToUpperInvariant();

        public static ConnectionInfo CreateConnectionInfo(this IContextFactoryService factory, ConnectionInfo connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            return factory.CreateConnectionInfo(connection.Protocol, connection.LocalIpAddress, connection.LocalPort, connection.RemoteIpAddress, connection.RemotePort);
        }


        public static DnsContext CreateContext(this IContextFactoryService factory, ConnectionInfo connection)
        {
            return factory.CreateContext(GenerateTraceIdentifier(), connection, null, false, default(CancellationToken));
        }

        public static DnsContext CreateContext(this IContextFactoryService factory, ConnectionInfo connection, IFeatureCollection featureCollection)
        {
            if (featureCollection == null)
            {
                throw new ArgumentNullException(nameof(featureCollection));
            }
            return factory.CreateContext(GenerateTraceIdentifier(), connection, featureCollection, featureCollection.IsReadOnly, default(CancellationToken));
        }

        public static DnsContext CreateContext(this IContextFactoryService factory, string traceIdentifier, ConnectionInfo connection)
        {
            return factory.CreateContext(traceIdentifier, connection, null, false, default(CancellationToken));
        }

        public static DnsContext CreateContext(this IContextFactoryService factory, string traceIdentifier, ConnectionInfo connection, IFeatureCollection featureCollection)
        {
            if (featureCollection == null)
            {
                throw new ArgumentNullException(nameof(featureCollection));
            }
            return factory.CreateContext(traceIdentifier, connection, featureCollection, featureCollection.IsReadOnly, default(CancellationToken));
        }

        public static DnsContext CreateContext(this IContextFactoryService factory, string traceIdentifier, ConnectionInfo connection, IEnumerable<KeyValuePair<Type, object>> builtInFeatures, bool featureCollectionReadOnly)
        {
            return factory.CreateContext(traceIdentifier, connection, builtInFeatures, featureCollectionReadOnly, default(CancellationToken));
        }
    }
}
